package org.glandais.birt.osgi.oda.util;

import java.util.Collection;
import java.util.Map;

import org.glandais.birt.osgi.Activator;
import org.glandais.birt.osgi.oda.definition.ResultDefinition;
import org.osgi.framework.Bundle;

import com.thoughtworks.xstream.XStream;

/**
 * The Class ClassTools.
 */
public class ClassTools {

	/** The xstream. */
	private static XStream xstream = null;

	/** The global class loader. */
	private static ClassLoader globalClassLoader = null;

	/**
	 * Instantiates a new class tools.
	 */
	private ClassTools() {
		super();
	}

	/**
	 * Checks if is multiple.
	 * 
	 * @param clazz
	 *            the clazz
	 * 
	 * @return true, if is multiple
	 */
	public static final boolean isMultiple(Class<?> clazz) {
		if (isCollection(clazz)) {
			return true;
		}
		if (isMap(clazz)) {
			return true;
		}
		return false;
	}

	/**
	 * Checks if is collection.
	 * 
	 * @param clazz
	 *            the clazz
	 * 
	 * @return true, if is collection
	 */
	public static final boolean isCollection(Class<?> clazz) {
		return checkHasInterface(clazz, Collection.class);
	}

	/**
	 * Checks if is map.
	 * 
	 * @param clazz
	 *            the clazz
	 * 
	 * @return true, if is map
	 */
	public static final boolean isMap(Class<?> clazz) {
		return checkHasInterface(clazz, Map.class);
	}

	/**
	 * Check has interface.
	 * 
	 * @param clazz
	 *            the clazz
	 * @param checkedInterface
	 *            the checked interface
	 * 
	 * @return true, if successful
	 */
	private static boolean checkHasInterface(Class<?> clazz,
			Class<?> checkedInterface) {
		Class<?>[] interfaces = clazz.getInterfaces();
		for (Class<?> anInterface : interfaces) {
			if (anInterface.equals(checkedInterface)) {
				return true;
			}
			if (checkHasInterface(anInterface, checkedInterface)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Parses the definition.
	 * 
	 * @param queryText
	 *            the query text
	 * 
	 * @return the result definition
	 */
	public static ResultDefinition parseDefinition(String queryText) {
		return (ResultDefinition) getXStream().fromXML(queryText);
	}

	/**
	 * Unparse definition.
	 * 
	 * @param definition
	 *            the definition
	 * 
	 * @return the string
	 */
	public static String unparseDefinition(ResultDefinition definition) {
		return getXStream().toXML(definition);
	}

	/**
	 * Gets the x stream.
	 * 
	 * @return the x stream
	 */
	private static XStream getXStream() {
		if (xstream == null) {
			initXStream();
		}
		return xstream;
	}

	/**
	 * Inits the x stream.
	 */
	private static void initXStream() {
		if (xstream == null) {
			xstream = new XStream();
			xstream
					.omitField(
							org.apache.commons.beanutils.BeanToPropertyValueTransformer.class,
							"log");
			try {
				xstream.setClassLoader(loadClassLoader());
			} catch (Throwable e) {
				// FIXME
				System.err.println("Failed to init class loader");
			}
		}
	}

	/**
	 * Load class loader.
	 * 
	 * @return the class loader
	 */
	private static ClassLoader loadClassLoader() {
		if (globalClassLoader == null) {
			initClassLoader();
		}
		return globalClassLoader;
	}

	/**
	 * Inits the class loader.
	 */
	private synchronized static void initClassLoader() {
		if (globalClassLoader == null) {
			ClassLoader classLoader = new CustomClassLoader();
			for (Bundle bundle : Activator.getDefault().getBundle()
					.getBundleContext().getBundles()) {
				ClassLoader classLoaderTemp = new CustomClassLoader(bundle,
						classLoader);
				classLoader = classLoaderTemp;
			}
			globalClassLoader = classLoader;
		}
	}

	public static Class<?> getClass(String resultClassName)
			throws ClassNotFoundException {
		Class<?> resultClass = loadClassLoader().loadClass(resultClassName);
		return resultClass;
	}

}
